#include "database/mysql_pool.h"
#include "LoggerManager.h"
#include <cppconn/exception.h>
#include <chrono>
#include <algorithm>

namespace cpp_backend
{
    namespace database
    {

        using namespace logger;

        // MySQLPool单例实现

        MySQLPool &MySQLPool::Instance()
        {
            static MySQLPool instance;
            return instance;
        }

        MySQLPool::~MySQLPool()
        {
            Shutdown();
        }

        bool MySQLPool::Initialize(const std::string &host, int port,
                                   const std::string &database,
                                   const std::string &username,
                                   const std::string &password,
                                   int pool_size)
        {
            std::lock_guard<std::mutex> lock(mutex_);

            if (!available_connections_.empty())
            {
                LOG_WARN << "MySQL pool already initialized";
                return true;
            }

            try
            {
                LOG_INFO << "Initializing MySQL connection pool...";
                LOG_INFO << "  Host: " << host << ":" << port;
                LOG_INFO << "  Database: " << database;
                LOG_INFO << "  Pool size: " << pool_size;

                host_ = host;
                port_ = port;
                database_ = database;
                username_ = username;
                password_ = password;
                pool_size_ = pool_size;
                shutdown_ = false;

                // 获取MySQL驱动
                driver_ = sql::mysql::get_mysql_driver_instance();
                if (!driver_)
                {
                    LOG_ERROR << "Failed to get MySQL driver instance";
                    return false;
                }

                // 创建初始连接
                int successful_connections = 0;
                int failed_connections = 0;

                for (int i = 0; i < pool_size_; ++i)
                {
                    sql::Connection *conn = CreateConnection();
                    if (conn)
                    {
                        available_connections_.push(
                            std::make_shared<MySQLConnection>(conn));
                        successful_connections++;
                        LOG_DEBUG << "Created MySQL connection " << (i + 1) << "/" << pool_size_;
                    }
                    else
                    {
                        failed_connections++;
                        LOG_WARN << "Failed to create MySQL connection " << (i + 1) << "/" << pool_size_;
                    }
                }

                // 定义最小连接数：至少需要pool_size的一半，但不少于1个
                int min_connections = std::max(1, pool_size_ / 2);

                // 检查是否达到最小连接数要求
                if (successful_connections < min_connections)
                {
                    LOG_ERROR << "MySQL pool initialization failed: "
                              << "Created " << successful_connections << " connections, "
                              << "but minimum required is " << min_connections;

                    // 清理已创建的连接
                    while (!available_connections_.empty())
                    {
                        available_connections_.pop();
                    }
                    return false;
                }

                // 初始化成功，但可能有部分连接失败
                if (failed_connections > 0)
                {
                    LOG_WARN << "MySQL connection pool initialized with warnings: "
                             << successful_connections << "/" << pool_size_ << " connections created "
                             << "(" << failed_connections << " failed)";
                }
                else
                {
                    LOG_INFO << "MySQL connection pool initialized successfully: "
                             << successful_connections << "/" << pool_size_ << " connections";
                }

                return true;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "MySQL initialization exception: " << e.what();
                LOG_ERROR << "  Error code: " << e.getErrorCode();
                LOG_ERROR << "  SQL state: " << e.getSQLState();
                return false;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "MySQL initialization exception: " << e.what();
                return false;
            }
        }

        sql::Connection *MySQLPool::CreateConnection()
        {
            try
            {
                // 构建连接字符串
                std::string conn_str = "tcp://" + host_ + ":" + std::to_string(port_);

                LOG_DEBUG << "Creating MySQL connection to " << conn_str;

                // 创建连接
                sql::Connection *conn = driver_->connect(conn_str, username_, password_);

                if (!conn)
                {
                    LOG_ERROR << "Failed to create MySQL connection";
                    return nullptr;
                }

                // 选择数据库
                conn->setSchema(database_);

                // 设置连接选项
                conn->setAutoCommit(true); // 默认自动提交

                // 设置字符集
                sql::Statement *stmt = conn->createStatement();
                stmt->execute("SET NAMES utf8mb4");
                delete stmt;

                LOG_DEBUG << "MySQL connection created successfully";
                return conn;
            }
            catch (sql::SQLException &e)
            {
                LOG_ERROR << "Create MySQL connection exception: " << e.what();
                LOG_ERROR << "  Error code: " << e.getErrorCode();
                return nullptr;
            }
        }

        MySQLConnectionPtr MySQLPool::GetConnection(int timeout_ms)
        {
            std::unique_lock<std::mutex> lock(mutex_);

            if (shutdown_)
            {
                LOG_ERROR << "MySQL pool is shutting down";
                return nullptr;
            }

            // 等待可用连接
            auto deadline = std::chrono::steady_clock::now() +
                            std::chrono::milliseconds(timeout_ms);

            while (available_connections_.empty() && !shutdown_)
            {
                if (timeout_ms > 0)
                {
                    if (cv_.wait_until(lock, deadline) == std::cv_status::timeout)
                    {
                        LOG_WARN << "Get MySQL connection timeout after " << timeout_ms << "ms";
                        return nullptr;
                    }
                }
                else
                {
                    cv_.wait(lock);
                }
            }

            if (shutdown_ || available_connections_.empty())
            {
                return nullptr;
            }

            // 获取连接
            MySQLConnectionPtr conn = available_connections_.front();
            available_connections_.pop();

            // 检查连接有效性
            if (!conn->IsValid())
            {
                LOG_WARN << "MySQL connection is invalid, creating new one";

                lock.unlock(); // 释放锁以避免阻塞其他线程

                sql::Connection *new_conn = CreateConnection();
                if (new_conn)
                {
                    conn = std::make_shared<MySQLConnection>(new_conn);
                }
                else
                {
                    LOG_ERROR << "Failed to create new MySQL connection";
                    return nullptr;
                }

                lock.lock(); // 重新获取锁
            }

            // 使用shared_ptr的自定义删除器，自动归还连接到池
            // 这样当shared_ptr销毁时，连接会自动归还
            MySQLConnectionPtr managed_conn(conn.get(),
                                            [this, conn](MySQLConnection *) mutable
                                            {
                                                // 归还连接到池
                                                std::lock_guard<std::mutex> guard(this->mutex_);
                                                if (!this->shutdown_ && conn && conn->IsValid())
                                                {
                                                    this->available_connections_.push(conn);
                                                    this->cv_.notify_one();
                                                    LOG_DEBUG << "Connection returned to pool, available: "
                                                              << this->available_connections_.size();
                                                }
                                            });

            return managed_conn;
        }

        void MySQLPool::ReturnConnection(MySQLConnectionPtr conn)
        {
            if (!conn)
            {
                return;
            }

            std::lock_guard<std::mutex> lock(mutex_);

            if (shutdown_)
            {
                return;
            }

            // 检查连接是否有效
            if (conn->IsValid())
            {
                available_connections_.push(conn);
            }
            else
            {
                LOG_WARN << "Returned connection is invalid, discarding";
                // 创建新连接补充
                sql::Connection *new_conn = CreateConnection();
                if (new_conn)
                {
                    available_connections_.push(std::make_shared<MySQLConnection>(new_conn));
                }
            }

            cv_.notify_one();
        }

        MySQLPool::PoolStats MySQLPool::GetStats() const
        {
            std::lock_guard<std::mutex> lock(mutex_);

            PoolStats stats;
            stats.total_connections = pool_size_;
            stats.available_connections = available_connections_.size();
            stats.active_connections = pool_size_ - available_connections_.size();

            return stats;
        }

        void MySQLPool::Shutdown()
        {
            std::lock_guard<std::mutex> lock(mutex_);

            if (shutdown_)
            {
                return;
            }

            LOG_INFO << "Shutting down MySQL connection pool...";

            shutdown_ = true;

            // 清空所有连接
            while (!available_connections_.empty())
            {
                available_connections_.pop();
            }

            cv_.notify_all();

            LOG_INFO << "MySQL connection pool shut down";
        }

    } // namespace database
} // namespace file_server
